home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Toolbox / Visual Basic Toolbox (P.I.E.)(1996).ISO / dialog / tabdlg3 / src / tabdlg3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-21  |  42.9 KB  |  1,486 lines

  1. //////////////////////////////////////////////////////////////////////////
  2. // TabDlg 3.0 
  3. // Copyright (c) 1994 Edward McCreary.
  4. // All rights reserved.
  5. //
  6. // Redistribution and use in source and binary forms are freely permitted
  7. // provided that the above copyright notice and attibution and date of work
  8. // and this paragraph are duplicated in all such forms.
  9. // THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
  10. // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  11. // WARRANTIES OF MERCHANTIBILILTY AND FITNESS FOR A PARTICULAR PURPOSE.
  12. ///////////////////////////////////////////////////////////////////////////
  13. // File:    tabdlg3.c
  14. // Author:  Ed McCreary
  15. // Date:    11/7/94
  16. // Purpose: custom control to implement Word 6.0 style tabs
  17. ///////////////////////////////////////////////////////////////////////////
  18. #define STRICT
  19. #include <windows.h>
  20. #include <windowsx.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include "tabdlg3.h"
  24. #include "internal.h"
  25.  
  26.  
  27. // global variables
  28.  
  29. // instance handle of this module
  30. HINSTANCE hInstance = NULL;
  31.  
  32. // font to used for depressed tabs
  33. HFONT     hDepressedFont = NULL;
  34.  
  35. // predefined class names for merging dialog box templates
  36. static char *szPredefinedClassNames[] =
  37.    { "BUTTON", "EDIT", "STATIC",
  38.    "LISTBOX", "SCROLLBAR", "COMBOBOX" };
  39.  
  40. ///////////////////////////////////////////////////////////////////////////
  41. // Function:    LibMain
  42. // Purpose:     main entry point for library
  43. // Parameters:  hInst   -   instance handle of library
  44. //              wDataSeg -  library data segment
  45. //              wHeapSize   default heap size
  46. //              lpszCmdLine command-line arguments
  47. //
  48. // Returns:     TRUE on success
  49. //              FALSE on failure
  50. ///////////////////////////////////////////////////////////////////////////
  51. BOOL WINAPI LibMain (HINSTANCE hInst, WORD wDataSeg,
  52.        WORD wHeapSize, LPSTR lpszCmdLine)
  53. {
  54.  if(wHeapSize != 0)
  55.   UnlockData(0);
  56.  
  57.  // store off dll instance handle 
  58.  hInstance = hInst;
  59.  
  60.  // to keep the compiler from bitching 
  61.  wDataSeg = wDataSeg;
  62.  lpszCmdLine = lpszCmdLine;
  63.  
  64.  // init tab library
  65.  if(!TabControlInit())
  66.  {
  67.     TabControlExit();
  68.     return FALSE;
  69.  }
  70.     
  71.  return TRUE;
  72. }
  73.  
  74.  
  75. ///////////////////////////////////////////////////////////////////////////
  76. // Function:    WEP
  77. // Purpose:     windows exit procuedure
  78. // Parameters:  nSystemExit exit code
  79. //
  80. // Returns:     1
  81. ///////////////////////////////////////////////////////////////////////////
  82. int WINAPI WEP(int nSystemExit)
  83. {
  84.   // cleanup after tab
  85.   TabControlExit();
  86.   return 1;
  87. }
  88.  
  89.  
  90. ///////////////////////////////////////////////////////////////////////////
  91. // Function:    TabControlInit
  92. // Purpose:     registers tab control class with Windows
  93. // Parameters:  none
  94. //
  95. // Returns:     TRUE  on success
  96. //              FALSE on failure
  97. ///////////////////////////////////////////////////////////////////////////
  98. BOOL WINAPI __export TabControlInit(void)
  99. {
  100.     WNDCLASS    wc;
  101.     LOGFONT     logfont;
  102.     HDC         hdc;
  103.     
  104.     // fill in class style
  105.     wc.style = TAB_CLASS;
  106.     wc.lpfnWndProc = TabDlgWndProc;
  107.     wc.cbClsExtra = 0;
  108.     wc.cbWndExtra = CBWNDEXTRA;
  109.     wc.hInstance = hInstance;
  110.     wc.hIcon = NULL;
  111.     wc.hCursor = LoadCursor(NULL,IDC_ARROW);
  112.     wc.hbrBackground = NULL;
  113.     wc.lpszMenuName = NULL;
  114.     wc.lpszClassName = TAB_CLASSNAME;
  115.     
  116.     if (!RegisterClass(&wc))  // register class
  117.         return FALSE;         // abort if failed
  118.     
  119.     hdc = GetDC(NULL);
  120.     // create font used to draw depressed tab titles    
  121.     // logfont.lfWeight = FW_THIN;
  122.     // 10 point height Sans Serif font (8 point for Win4)
  123.     memset(&logfont,0,sizeof(logfont));
  124.     logfont.lfWeight = FW_NORMAL;
  125.     logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  126.     logfont.lfHeight = -MulDiv(8, GetDeviceCaps(hdc,LOGPIXELSY), 72);
  127.     lstrcpy(logfont.lfFaceName, "MS Sans Serif");
  128.     
  129.     ReleaseDC(NULL,hdc);
  130.     // bang
  131.     hDepressedFont =  CreateFontIndirect(&logfont);
  132.  
  133.     return TRUE;  // return success
  134. }
  135.  
  136. ///////////////////////////////////////////////////////////////////////////
  137. // Function:    TabControlExit
  138. // Purpose:     unregisters tab class with windows
  139. // Parameters:  none
  140. //
  141. // Returns:     n/a
  142. ///////////////////////////////////////////////////////////////////////////
  143. void WINAPI __export TabControlExit(void)
  144. {
  145.     // unregister class with windows
  146.     UnregisterClass(TAB_CLASSNAME,hInstance);
  147.     
  148.     // destroy font object if needed
  149.     if(hDepressedFont)
  150.         DeleteObject(hDepressedFont);
  151. }
  152.  
  153.  
  154. ///////////////////////////////////////////////////////////////////////////
  155. // Function:    TabDlgWndProc
  156. // Purpose:     main callback for tab control
  157. // Parameters:  hWnd    - window handle
  158. //              uMsg    - message
  159. //              wParam  - word size parameter
  160. //              lParam  - dword size parameter
  161. //
  162. // Returns:     msg dependent
  163. ///////////////////////////////////////////////////////////////////////////
  164. LRESULT WINAPI __export TabDlgWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  165. {
  166.     LPTABCTLBLK pData = NULL;
  167.     LRESULT     dwReturn;
  168.  
  169.     // get pointer to memory block used to store tab information    
  170.     // this is create during WM_NCCREATE
  171.     if(uMsg != WM_NCCREATE)
  172.         pData = (LPTABCTLBLK)GlobalLock((HGLOBAL)GetWindowWord(hWnd,GWW_DATA));
  173.  
  174.     switch(uMsg)
  175.     {
  176.         case WM_NCCREATE:
  177.             dwReturn = OnNCCreate(hWnd, (CREATESTRUCT FAR *)lParam);
  178.         break;
  179.         
  180.         case WM_NCDESTROY:
  181.             dwReturn = OnNCDestroy(pData);        
  182.         break;
  183.         
  184.         case WM_CREATE:
  185.             {
  186.              // make sure window has transparent style bit on
  187.              LONG   lStyle;
  188.              
  189.              lStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
  190.              lStyle |= WS_EX_TRANSPARENT;
  191.              SetWindowLong(hWnd,GWL_EXSTYLE, lStyle);             
  192.              
  193.              dwReturn = DefWindowProc(hWnd,uMsg,wParam,lParam);
  194.             }
  195.         break;
  196.         
  197.         case WM_KEYDOWN:
  198.         switch(wParam)
  199.         {   
  200.             // rotate tab one left
  201.             case VK_LEFT:
  202.             if(pData->pActiveTab && pData->pActiveTab->prev)
  203.                 dwReturn = SendMessage(hWnd,TAB_SETCURSEL,pData->pActiveTab->prev->wIndex, 0L);
  204.             break;
  205.             
  206.             // rotate tab one right
  207.             case VK_RIGHT:
  208.             if(pData->pActiveTab && pData->pActiveTab->next)
  209.                 dwReturn = SendMessage(hWnd,TAB_SETCURSEL,pData->pActiveTab->next->wIndex, 0L);            
  210.             break;        
  211.         }        
  212.         break;
  213.         
  214.         case WM_SETFONT:
  215.             {
  216.                 LPTABPAGE   ptr;
  217.                 
  218.                 // store font
  219.                 SetWindowWord(hWnd, GWW_FONT,wParam);
  220.                 
  221.                 // calculate height of tabs
  222.                 pData->wTabHeight = CalcTabHeight(hWnd);
  223.                 
  224.                 // set new tab width                
  225.                 SetWindowWord(hWnd,GWW_TABWIDTH,CalcTabWidth(pData));
  226.                 // update tab rects
  227.                 for(ptr = pData->lpHead; ptr != NULL; ptr = ptr->next)
  228.                     CalcTabRect(pData,ptr);
  229.                 
  230.                 // if lParam not zero, update window    
  231.                 if(lParam)
  232.                     InvalidateRect(hWnd, NULL, FALSE);
  233.                 
  234.                 dwReturn = DefWindowProc(hWnd,uMsg,wParam,lParam);
  235.             }
  236.         break;
  237.         
  238.         // draw focus rect around caption of active tab when needed
  239.         case WM_SETFOCUS:
  240.         case WM_KILLFOCUS:
  241.         {
  242.          HDC    hdc;
  243.          
  244.          hdc = GetDC(hWnd);
  245.             if(pData->pActiveTab)
  246.                 DrawFocusRect(hdc,&pData->pActiveTab->rcCaption);   
  247.          ReleaseDC(hWnd,hdc);         
  248.          dwReturn = DefWindowProc(hWnd,uMsg,wParam,lParam);
  249.         }        
  250.         break;
  251.         
  252.         
  253.         case WM_GETFONT:
  254.             dwReturn = GetWindowWord(hWnd,GWW_FONT);
  255.         break;
  256.         
  257.         case WM_GETDLGCODE:
  258.             dwReturn = DLGC_WANTARROWS;        
  259.         break;
  260.         
  261.         case WM_PAINT:
  262.             dwReturn = OnPaint(pData);
  263.         break;
  264.  
  265.         case WM_LBUTTONDOWN:
  266.         {
  267.             POINT   pt;
  268.             
  269.             pt.x = LOWORD(lParam);
  270.             pt.y = HIWORD(lParam);
  271.                                 
  272.             dwReturn = OnLButtonDown(pData, &pt);
  273.         }
  274.         break;
  275.         
  276.         case TAB_ADDTAB:
  277.             dwReturn = OnAddTab(pData, wParam, lParam);
  278.         break;
  279.         
  280.         case TAB_SETCURSEL:        
  281.             dwReturn = OnSetCurSel(pData,wParam);
  282.         break;
  283.         
  284.         case TAB_GETCURSEL:        
  285.             dwReturn = pData->pActiveTab->wIndex;
  286.         break;
  287.  
  288.         case TAB_GETCOUNT:        
  289.             dwReturn = pData->wNumTabs;
  290.         break;
  291.  
  292.         case TAB_DELETETAB:
  293.             dwReturn = OnDeleteTab(pData,wParam);                    
  294.         break;
  295.       
  296.         case TAB_FINDTAB:
  297.             dwReturn = OnFindTab(pData,(LPCSTR)lParam);
  298.         break;
  299.  
  300.         case TAB_GETTEXTLEN:
  301.             dwReturn = OnGetTextLength(pData,wParam);
  302.         break;
  303.  
  304.         case TAB_GETTEXT:
  305.             dwReturn = OnGetText(pData,wParam,(LPSTR)lParam);
  306.         break;
  307.  
  308.         default:
  309.             dwReturn = DefWindowProc(hWnd,uMsg,wParam,lParam);
  310.     }
  311.  
  312.     // unlock control block
  313.     if(uMsg != WM_NCDESTROY)
  314.         GlobalUnlock((HGLOBAL)GetWindowWord(hWnd,0));
  315.  
  316.     return dwReturn;
  317. }
  318.  
  319.  
  320.  
  321. ///////////////////////////////////////////////////////////////////////////
  322. // Function:    DrawBorder
  323. // Purpose:     draw border around control
  324. // Parameters:  hdc     - device context
  325. //              lprc    - control rect
  326. //              pData   - pointer to tab control block
  327. //              pPens   - array of pens need for drawing
  328. //
  329. // Returns:     n/a
  330. ///////////////////////////////////////////////////////////////////////////
  331. void WINAPI DrawBorder(HDC hdc, LPRECT lprc, LPTABCTLBLK pData, HPEN *pPens)
  332. {
  333.     POINT  pt[4];
  334.     HPEN   hOldPen;
  335.     RECT   rc;
  336.  
  337.     // copy the rect
  338.     CopyRect(&rc,lprc);
  339.     
  340.     // offset top by height of tap
  341.     rc.top += (pData->wTabHeight - 1);
  342.     
  343.     // now draw the u shaped frame 
  344.     hOldPen = SelectObject(hdc, pPens[PEN_BLACK]);
  345.     
  346.     // black frame
  347.     pt[0].x = rc.left;
  348.     pt[0].y = rc.top;
  349.     pt[1].x = rc.left;
  350.     pt[1].y = rc.bottom;
  351.     pt[2].x = rc.right;
  352.     pt[2].y = rc.bottom;
  353.     pt[3].x = rc.right;
  354.     pt[3].y = rc.top-1; // make sure they connect
  355.  
  356.     Polyline(hdc,(LPPOINT)&pt,4);
  357.  
  358.     SelectObject(hdc,pPens[PEN_WHITE]);
  359.     
  360.     // two white border lines
  361.     pt[0].x = rc.left+1;
  362.     pt[0].y = rc.top;
  363.     pt[1].x = rc.left+1;
  364.     pt[1].y = rc.bottom-1;
  365.  
  366.     Polyline(hdc,(LPPOINT)&pt,2);
  367.  
  368.     pt[0].x = rc.left+2;
  369.     pt[0].y = rc.top;
  370.     pt[1].x = rc.left+2;
  371.     pt[1].y = rc.bottom-2;
  372.     Polyline(hdc,(LPPOINT)&pt,2);
  373.  
  374.     SelectObject(hdc,pPens[PEN_SHADOW]);
  375.     
  376.     // two shadow lines
  377.     pt[0].x = rc.left + 1;
  378.     pt[0].y = rc.bottom - 1;
  379.     pt[1].x = rc.right-1;
  380.     pt[1].y = rc.bottom - 1;
  381.     pt[2].x = rc.right - 1;
  382.     pt[2].y = rc.top - 1;
  383.  
  384.     Polyline(hdc,(LPPOINT)&pt,3);
  385.  
  386.     pt[0].x = rc.left + 2;
  387.     pt[0].y = rc.bottom - 2;
  388.     pt[1].x = rc.right-2;
  389.     pt[1].y = rc.bottom - 2;
  390.     pt[2].x = rc.right - 2;
  391.     pt[2].y = rc.top - 1;
  392.     Polyline(hdc,(LPPOINT)&pt,3);
  393.  
  394.     // restore old pen 
  395.     SelectObject(hdc,hOldPen);
  396. }
  397. ///////////////////////////////////////////////////////////////////////////
  398. // Function:    CalcTabHeight
  399. // Purpose:     calculates height of tab based upon current system font
  400. // Parameters:  none
  401. //
  402. // Returns:     height of tab in pixels
  403. ///////////////////////////////////////////////////////////////////////////
  404. WORD WINAPI CalcTabHeight(HWND hWnd)
  405. {
  406.     HDC hdc;
  407.     TEXTMETRIC  tm;
  408.     HFONT   hOldFont;
  409.     
  410.     hdc = GetDC(NULL);
  411.     hOldFont = (HFONT)SelectObject(hdc,GetActiveTabFont(hWnd));    
  412.     GetTextMetrics(hdc,&tm);
  413.     SelectObject(hdc,hOldFont);
  414.     ReleaseDC(NULL,hdc);
  415.     
  416.     return tm.tmHeight + tm.tmHeight/2 + 4;
  417. }
  418.  
  419. ///////////////////////////////////////////////////////////////////////////
  420. // Function:    GetActiveTabFont
  421. // Purpose:     returns handle to font to used for active tab
  422. // Parameters:  none
  423. //
  424. // Returns:     handle to font
  425. ///////////////////////////////////////////////////////////////////////////
  426. HFONT WINAPI GetActiveTabFont(HWND hWnd)
  427. {
  428.     HFONT   hFont;
  429.     
  430.     hFont = (HFONT)GetWindowWord(hWnd,GWW_FONT);
  431.     
  432.     // use system font if no font stored in window
  433.     if(!IsGDIObject(hFont))
  434.         hFont = (HFONT)GetStockObject(SYSTEM_FONT);
  435.  
  436.     return hFont;
  437. }
  438.  
  439. ///////////////////////////////////////////////////////////////////////////
  440. // Function:    GetDepressedTabFont
  441. // Purpose:     returns handle to font to used for depressed tab
  442. // Parameters:  none
  443. //
  444. // Returns:     handle to font
  445. ///////////////////////////////////////////////////////////////////////////
  446. HFONT WINAPI __export GetDepressedTabFont(void)
  447. {
  448.     // use system font if no depressed font created
  449.     if(!IsGDIObject(hDepressedFont))
  450.         return (HFONT)GetStockObject(SYSTEM_FONT);
  451.     else
  452.         return hDepressedFont;
  453. }
  454.  
  455.  
  456. ///////////////////////////////////////////////////////////////////////////
  457. // Function:    OnNCCreate
  458. // Purpose:     responds to WM_NCCREATE
  459. // Parameters:  hWnd    - control window
  460. //              lpcs    - create struct
  461. //
  462. // Returns:     return value
  463. ///////////////////////////////////////////////////////////////////////////
  464. LRESULT WINAPI OnNCCreate(HWND hWnd, CREATESTRUCT FAR *lpcs)
  465. {
  466.     HGLOBAL hGlobal;
  467.     LPTABCTLBLK pData = NULL;
  468.             
  469.     // allocate new block of memory for control info
  470.     if(!(hGlobal = GlobalAlloc(GHND,sizeof(TABCTLBLK))))
  471.           return 0L;                                         // abort if error
  472.             
  473.     // store in window extra bytes
  474.     SetWindowWord(hWnd,GWW_DATA,(WORD)hGlobal);
  475.             
  476.     // get a pointer to it
  477.     pData = (LPTABCTLBLK)GlobalLock(hGlobal);
  478.     
  479.     // save window handle so we don't have to pass it around
  480.     pData->hWnd = hWnd;
  481.             
  482.     // store style bits
  483.     if(LOWORD(lpcs->style) & TBS_SHADOW)
  484.         pData->bShadow = TRUE;
  485.      else
  486.         pData->bShadow = FALSE;
  487.     
  488.     // clear rest of the struct members
  489.     pData->lpHead = pData->lpTail = NULL;
  490.     pData->wNumTabs = 0;
  491.             
  492.     // calculate height of tabs
  493.     pData->wTabHeight = CalcTabHeight(hWnd);
  494.     
  495.     // use default return value
  496.     return DefWindowProc(hWnd,WM_NCCREATE,0,(LPARAM)lpcs);           
  497. }
  498.  
  499. ///////////////////////////////////////////////////////////////////////////
  500. // Function:    OnPaint
  501. // Purpose:     repsonds to WM_PAINT
  502. // Parameters:  hWnd - window handle
  503. //              pData - tab control block
  504. //
  505. // Returns:     std return value
  506. ///////////////////////////////////////////////////////////////////////////
  507. LRESULT WINAPI OnPaint(LPTABCTLBLK pData)
  508. {
  509.     HDC    hdc;
  510.     PAINTSTRUCT ps;
  511.     RECT   rc;
  512.     HPEN   pens[3];
  513.     LPTABPAGE   ptr;
  514.     HPEN   hOldPen;
  515.     
  516.     
  517.     // get pens needed for drawing
  518.     pens[PEN_WHITE] = (HPEN)GetStockObject(WHITE_PEN);
  519.     pens[PEN_BLACK] = (HPEN)GetStockObject(BLACK_PEN);
  520.     pens[PEN_SHADOW] = CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNSHADOW));
  521.     
  522.     // get bounding rect
  523.     GetClientRect(pData->hWnd,&rc);
  524.     
  525.     // to keep everything inside borders    
  526.     rc.right--;
  527.     rc.bottom--;
  528.     
  529.     // start painting
  530.     hdc = BeginPaint(pData->hWnd,&ps);
  531.     
  532.     // draw border around control
  533.     DrawBorder(hdc,&rc,pData,pens);    
  534.     
  535.     // get pointer to head of tab list
  536.     ptr = pData->lpHead;
  537.     
  538.     // while ptr is valid
  539.     while(ptr)
  540.     {
  541.      // draw tab up if is active tab     
  542.      if(ptr == pData->pActiveTab)
  543.         DrawUpTab(hdc,pData,ptr,pens);
  544.      else
  545.         DrawDownTab(hdc,pData,ptr,pens);
  546.      
  547.      // draw caption
  548.      DrawTabText(hdc,pData,ptr);
  549.      
  550.      // get pointer to next tab in list
  551.      ptr = ptr->next;   
  552.     }
  553.     
  554.     // fill in horizontal lines
  555.     
  556.     // if first tab isn't the active tab...
  557.     if(pData->pActiveTab->wIndex != 0)
  558.     {        
  559.         hOldPen = (HPEN)SelectObject(hdc,pens[PEN_BLACK]);
  560.         MoveTo(hdc,rc.left,pData->wTabHeight - 2);
  561.         LineTo(hdc, pData->pActiveTab->rcTab.left,pData->wTabHeight - 2);   
  562.         
  563.         SelectObject(hdc,pens[PEN_WHITE]);
  564.         MoveTo(hdc,rc.left + 1,pData->wTabHeight - 1);
  565.         LineTo(hdc, pData->pActiveTab->rcTab.left + 1,pData->wTabHeight - 1);   
  566.  
  567.         MoveTo(hdc,rc.left + 1,pData->wTabHeight);
  568.         LineTo(hdc, pData->pActiveTab->rcTab.left + 1,pData->wTabHeight);   
  569.         
  570.         SelectObject(hdc,hOldPen);
  571.     }
  572.     
  573.     // if edge of last tab is less than the edge of the control...
  574.     if(pData->pActiveTab->rcTab.right < rc.right)
  575.     {
  576.         hOldPen = (HPEN)SelectObject(hdc,pens[PEN_BLACK]);
  577.         MoveTo(hdc,pData->pActiveTab->rcTab.right,pData->wTabHeight - 2);
  578.         LineTo(hdc, rc.right + 1,pData->wTabHeight - 2);   
  579.         
  580.         SelectObject(hdc,pens[PEN_WHITE]);
  581.         MoveTo(hdc,pData->pActiveTab->rcTab.right,pData->wTabHeight - 1);
  582.         LineTo(hdc, rc.right,pData->wTabHeight - 1);   
  583.  
  584.         MoveTo(hdc,pData->pActiveTab->rcTab.right - 1,pData->wTabHeight);
  585.         LineTo(hdc, rc.right - 1,pData->wTabHeight);   
  586.         
  587.         SelectObject(hdc,hOldPen);
  588.     }
  589.     
  590.     // cleanup
  591.     EndPaint(pData->hWnd,&ps);
  592.     DeleteObject(pens[PEN_SHADOW]);
  593.     
  594.     return 0L;
  595. }
  596.  
  597. ///////////////////////////////////////////////////////////////////////////
  598. // Function:    OnAddTab
  599. // Purpose:     responds to TAB_ADDTAB, adds new tab to control
  600. // Parameters:  pData   - pointer to tab control block
  601. //              wParam, lParam - callback parameters
  602. //
  603. // Returns:     TRUE    -   on success
  604. //              FALSE   -   on failure
  605. ///////////////////////////////////////////////////////////////////////////
  606. LRESULT WINAPI OnAddTab(LPTABCTLBLK pData, WPARAM wParam, LPARAM lParam)
  607. {
  608.     LPDLGTEMPLATE   lpDlgTemplate;
  609.     HRSRC hrsrcDialog;
  610.     HGLOBAL hGlblDlgTemplate;
  611.     BOOL    bResult;
  612.     int     index;
  613.     
  614.     // trivial abort
  615.     if(!lParam)
  616.         return FALSE;
  617.     
  618.     
  619.     if(wParam)  // must be hInstance of module to load template from
  620.     {
  621.         hrsrcDialog = FindResource((HINSTANCE)wParam, (LPCSTR)lParam, RT_DIALOG);
  622.         if (hrsrcDialog == NULL) 
  623.             return FALSE;
  624.         
  625.         hGlblDlgTemplate = LoadResource((HINSTANCE)wParam, hrsrcDialog);
  626.         lpDlgTemplate = (LPDLGTEMPLATE) LockResource(hGlblDlgTemplate);
  627.         if (lpDlgTemplate == NULL) 
  628.             return(FALSE);    
  629.     }
  630.     else       // user passed a handle to an in-memory dialog template
  631.     {          // just lock it down      
  632.       lpDlgTemplate = (LPDLGTEMPLATE)GlobalLock((HGLOBAL)lParam);
  633.       if(lpDlgTemplate == NULL)
  634.         return FALSE;
  635.     }
  636.     
  637.     // go ahead and create tab
  638.     if( (index = CreateNewTab(pData,lpDlgTemplate)) == -1)
  639.         bResult = FALSE;
  640.     else
  641.         bResult = TRUE;
  642.    
  643.     // set current selection to new tab
  644.     SendMessage(pData->hWnd,TAB_SETCURSEL,(WPARAM)index,0L);
  645.     
  646.     // free template if we loaded it
  647.     if(wParam)
  648.     {
  649.          UnlockResource(hGlblDlgTemplate);   
  650.          FreeResource(hGlblDlgTemplate);   
  651.     } 
  652.    
  653.    return bResult;
  654. }
  655.  
  656. ///////////////////////////////////////////////////////////////////////////
  657. // Function:    CreateNewTab
  658. // Purpose:     builds new tab from template
  659. // Parameters:  pData   -   pointer to tab control block
  660. //              lpDlgTemplate - pointer to dlg template
  661. //
  662. // Returns:     index   -   on sucess
  663. //              -1      -   on failure
  664. ///////////////////////////////////////////////////////////////////////////
  665. int WINAPI __export CreateNewTab(LPTABCTLBLK pData,LPDLGTEMPLATE lpDlgTemplate)
  666. {
  667.  LPTABPAGE  pTabPage = NULL;
  668.  LPTABPAGE   ptr; 
  669.  
  670.  // alloc room for page
  671.  pTabPage = (LPTABPAGE)malloc(sizeof(TABPAGE));
  672.  
  673.  // abort
  674.  if(pTabPage == NULL)
  675.     return -1;
  676.  
  677.  // clear   
  678.  memset(pTabPage,0,sizeof(TABPAGE));
  679.  
  680.  // create the controls that belong to tab  
  681.  if(!CreateTabControls(pData,pTabPage,lpDlgTemplate))
  682.  {    
  683.     FreeTab(pTabPage);
  684.     return -1;
  685.  }
  686.  
  687.  // if this is the first tab created...
  688.  if(pData->lpHead == NULL)
  689.  {
  690.     pData->lpHead = pData->lpTail = pTabPage;
  691.     pTabPage->next = pTabPage->prev = NULL;    
  692.  }
  693.  else   // append to end of list
  694.  {
  695.     pData->lpTail->next = pTabPage;
  696.     pTabPage->prev = pData->lpTail;
  697.     pTabPage->next = NULL;
  698.     pData->lpTail = pTabPage; 
  699.  }  
  700.  
  701.  // set index
  702.  pTabPage->wIndex = pData->wNumTabs;
  703.  
  704.  // increment number of tabs
  705.  pData->wNumTabs++;
  706.  
  707.  // set new tab width                
  708.  SetWindowWord(pData->hWnd,GWW_TABWIDTH,CalcTabWidth(pData));
  709.  
  710.  // update tab rects
  711.  for(ptr = pData->lpHead; ptr != NULL; ptr = ptr->next)
  712.     CalcTabRect(pData,ptr);
  713.  
  714.  // return index to tab
  715.  return pTabPage->wIndex;
  716. }
  717.  
  718. ///////////////////////////////////////////////////////////////////////////
  719. // Function:    AppendControlToTab
  720. // Purpose:     adds new control to list of controls in tab
  721. // Parameters:  pTab    -   pointer to tab
  722. //              nID     -   id of control to add to list
  723. //
  724. // Returns:     TRUE    -   on sucess
  725. //              FALSE   -   on failure
  726. ///////////////////////////////////////////////////////////////////////////
  727. BOOL WINAPI __export AppendControlToTab(LPTABPAGE pTab, WORD nID)
  728. {
  729.     LPTABCHILDCTL   pControl;
  730.     LPTABCHILDCTL   ptr;
  731.  
  732.     pControl = (LPTABCHILDCTL)malloc(sizeof(TABCHILDCTL));
  733.     if(pControl == NULL)
  734.         return FALSE;
  735.     
  736.     pControl->wID = nID;
  737.     pControl->next = NULL;
  738.     
  739.     if(pTab->lpControls == NULL)    
  740.      pTab->lpControls = pControl;
  741.     else
  742.     {
  743.      ptr = pTab->lpControls;
  744.      while(ptr->next != NULL)
  745.         ptr = ptr->next;
  746.       
  747.      ptr->next = pControl;
  748.     }
  749.    
  750.    return TRUE;    
  751. }
  752.  
  753. ///////////////////////////////////////////////////////////////////////////
  754. // Function:    CreateTabControls
  755. // Purpose:     creates each control in template and adds to tab's list of
  756. //              controls
  757. // Parameters:  pData   -   pointer tab control block
  758. //              pTab    -   pointer to tab
  759. //              lpDlgTemplate   -   pointer to dlg template
  760. //
  761. // Returns:     TRUE    -   on sucess
  762. //              FALSE   -   on failure
  763. ///////////////////////////////////////////////////////////////////////////
  764. BOOL WINAPI __export CreateTabControls(LPTABCTLBLK pData, LPTABPAGE pTab, LPDLGTEMPLATE lpDlgTemplate)
  765. {
  766.    HWND hWndPrevChild;
  767.    HWND hDlg;
  768.    HFONT hFont;
  769.    LPBYTE p, lpszClass, lpszText, lpCreateParams;   
  770.    LPFONTINFO lpFontInfo;
  771.    HWND hWndChild;
  772.    BYTE bNumControls;   
  773.    LPDLGITEMTEMPLATE lpDlgItemTemplate;
  774.    RECT rc;
  775.    int  length;
  776.    
  777.    hDlg = GetParent(pData->hWnd);   
  778.    hWndPrevChild = GetWindow(hDlg,GW_CHILD);
  779.    
  780.    hFont = GetWindowFont(hDlg);
  781.  
  782.    // Ignore everything in Dialog Template except for the number 
  783.    // of controls.
  784.    bNumControls = lpDlgTemplate->dtItemCount;
  785.  
  786.    p = (LPBYTE) (&lpDlgTemplate->dtCY + 1);  // Start of Menu name
  787.    while (*p++ != 0) ;           // Skip the menu name string
  788.  
  789.    // p should pointer to caption
  790.    length = lstrlen(p);
  791.    pTab->szCaption = (char *)malloc(length + 1);
  792.    if(pTab->szCaption)
  793.     lstrcpy(pTab->szCaption,p);
  794.  
  795.    while (*p++ != 0) ;           // Skip the Class name string
  796.    
  797.    while (*p++ != 0) ;           // Skip the Caption string
  798.  
  799.    lpFontInfo = (LPFONTINFO) p;  // Start of FONTINFO (if exists)
  800.  
  801.    // Find address of first DLGITEMTEMPLATE structure
  802.    if (lpDlgTemplate->dtStyle & DS_SETFONT) {
  803.       p = (LPBYTE) (&lpFontInfo->PointSize + 1);
  804.       while (*p++ != 0) ;  // Skip the Type face name string
  805.       lpDlgItemTemplate = (LPDLGITEMTEMPLATE) p;
  806.    } else lpDlgItemTemplate = (LPDLGITEMTEMPLATE) lpFontInfo;
  807.  
  808.    // Create all of the child controls
  809.    while (bNumControls-- != 0) {
  810.  
  811.       lpszClass = (LPBYTE) (&lpDlgItemTemplate->dtilStyle + 1);
  812.       if (*lpszClass & PREDEFINEDCNTRLBIT) {
  813.          lpszText = lpszClass + 1;
  814.          lpszClass = (LPBYTE) szPredefinedClassNames
  815.             [(WORD)(*lpszClass) - PREDEFINEDCNTRLBIT];
  816.       } else for (lpszText = lpszClass; *lpszText++ != 0; ) ;
  817.  
  818.       // Find address of number-of-bytes-in-additional-data
  819.       for (lpCreateParams = lpszText; *lpCreateParams++ != 0; ) ;
  820.       
  821.       if (lpDlgItemTemplate->dtilID == (int)GetWindowWord(pData->hWnd,GWW_ID))
  822.             goto NextControl;
  823.  
  824.       /* add control to list in tab */      
  825.       
  826.       // give control unique id if -1
  827.           if(lpDlgItemTemplate->dtilID == (WORD)-1)
  828.             {
  829.                 pData->wStaticCount++;
  830.                 lpDlgItemTemplate->dtilID = ((WORD)-1) - pData->wStaticCount;        
  831.             }
  832.  
  833.       if(!AppendControlToTab(pTab,lpDlgItemTemplate->dtilID))
  834.         return FALSE;
  835.       
  836.       SetRect(&rc, lpDlgItemTemplate->dtilX,
  837.          lpDlgItemTemplate->dtilY,
  838.          lpDlgItemTemplate->dtilX + lpDlgItemTemplate->dtilCX,
  839.          lpDlgItemTemplate->dtilY + lpDlgItemTemplate->dtilCY);
  840.       MapDialogRect(hDlg, &rc);
  841.  
  842.       hWndChild = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
  843.          (LPCSTR) lpszClass, (LPCSTR) lpszText,
  844.          lpDlgItemTemplate->dtilStyle,
  845.          rc.left, rc.top,
  846.          rc.right - rc.left, rc.bottom - rc.top,
  847.          hDlg, (HMENU) lpDlgItemTemplate->dtilID, 
  848.          (HINSTANCE)GetWindowWord(pData->hWnd,GWW_HINSTANCE),
  849.          lpCreateParams + 1); // +1 to point to 1st byte of data
  850.  
  851.       if (hWndChild == NULL)
  852.          return(FALSE);      
  853.  
  854.       // Tell the new control to use the same font as dialog box
  855.       SetWindowFont(hWndChild, hFont, FALSE);
  856.  
  857.       // Fix the Z-Order of the controls
  858.       SetWindowPos(hWndChild, hWndPrevChild, 0, 0, 0, 0,
  859.          SWP_NOMOVE | SWP_NOSIZE);
  860.  
  861.       hWndPrevChild = hWndChild;
  862.       
  863.       NextControl:
  864.       // Point to the next DlgItemTemplate
  865.       lpDlgItemTemplate = (LPDLGITEMTEMPLATE)
  866.          (lpCreateParams + 1 + *lpCreateParams);
  867.    }
  868.  
  869.     return TRUE;
  870. }
  871.  
  872.  
  873. ///////////////////////////////////////////////////////////////////////////
  874. // Function:    FreeTab
  875. // Purpose:     frees memory associated with tab
  876. //              note that pointer is no longer valid
  877. // Parameters:  pTab    -   pointer to tab to free
  878. //
  879. // Returns:     n/a
  880. ///////////////////////////////////////////////////////////////////////////
  881. void WINAPI FreeTab(LPTABPAGE pTab)
  882. {
  883.  LPTABCHILDCTL   ptr;
  884.  LPTABCHILDCTL   prev;
  885.  
  886.  prev = pTab->lpControls;
  887.  while(prev != NULL)
  888.  {
  889.   ptr = prev->next;
  890.   free(prev);
  891.   prev = ptr; 
  892.  }
  893.  
  894.  free(pTab->szCaption);
  895.  free(pTab);
  896. }
  897.  
  898. ///////////////////////////////////////////////////////////////////////////
  899. // Function:    OnNCDestroy
  900. // Purpose:     responds to WM_NCDESTROY
  901. // Parameters:  pData   -   tab control block
  902. //
  903. // Returns:     std result
  904. ///////////////////////////////////////////////////////////////////////////
  905. LRESULT WINAPI OnNCDestroy(LPTABCTLBLK pData)
  906. {
  907.     LPTABPAGE  ptr;
  908.     LPTABPAGE  prev;
  909.     HWND       hWnd;
  910.  
  911.     prev = pData->lpHead;
  912.     while(prev != NULL)
  913.     {
  914.         ptr = prev->next;
  915.         FreeTab(prev);
  916.         prev = ptr; 
  917.     }
  918.  
  919.  
  920.     hWnd = pData->hWnd;
  921.      
  922.     GlobalUnlock((HGLOBAL)GetWindowWord(hWnd,0));
  923.     GlobalFree((HGLOBAL)GetWindowWord(hWnd,0));
  924.     SetWindowWord(hWnd,GWW_DATA,0);
  925.  
  926.     // use default return value
  927.     return DefWindowProc(hWnd,WM_NCDESTROY,0,0L);           
  928. }
  929.  
  930.  
  931. ///////////////////////////////////////////////////////////////////////////
  932. // Function:    GetTabPtrByIndex
  933. // Purpose:     returns pointer to tab based upon index
  934. // Parameters:  pData   -   pointer to tab control block
  935. //              wIndex  -   index of tab to find
  936. //
  937. // Returns:     pointer to tab  -   on success
  938. //              NULL            -   on failure
  939. ///////////////////////////////////////////////////////////////////////////
  940. LPTABPAGE WINAPI GetTabPtrByIndex(LPTABCTLBLK pData, WORD wIndex)
  941. {
  942.     LPTABPAGE pTab;
  943.     
  944.     pTab = pData->lpHead;
  945.     while(pTab)
  946.     {
  947.      if(pTab->wIndex == wIndex)
  948.         return pTab;
  949.     
  950.      pTab = pTab->next;
  951.     }
  952.  
  953.    return NULL;
  954. }
  955.  
  956.  
  957. ///////////////////////////////////////////////////////////////////////////
  958. // Function:    OnSetCurSel
  959. // Purpose:     responds to TAB_SETCURSEL
  960. // Parameters:  pData   -   pointer to tab control block
  961. //              wIndex  -   index of tab to set
  962. //
  963. // Returns:     std return value
  964. ///////////////////////////////////////////////////////////////////////////
  965. LRESULT WINAPI OnSetCurSel(LPTABCTLBLK pData, WORD wIndex)
  966. {
  967.     LPTABPAGE pTab;
  968.     UINT    uFlags;
  969.     LPTABCHILDCTL   ptr;
  970.     HWND    hDlg;
  971.     RECT    rc;
  972.     
  973.     uFlags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
  974.                SWP_NOZORDER;
  975.  
  976.     
  977.     hDlg = GetParent(pData->hWnd);
  978.     
  979.     pTab = GetTabPtrByIndex(pData,wIndex);
  980.     if(pTab)
  981.     {
  982.         // hide controls of current top tab
  983.         if(pData->pActiveTab)
  984.         {
  985.          ptr = pData->pActiveTab->lpControls;
  986.          
  987.          while(ptr)
  988.          {
  989.           SetWindowPos(GetDlgItem(hDlg,ptr->wID),NULL,0,0,0,0,
  990.                 uFlags | SWP_HIDEWINDOW);
  991.  
  992.           ptr = ptr->next;
  993.          } 
  994.          
  995.          // update area of tab         
  996.          CopyRect(&rc, &pData->pActiveTab->rcTab);
  997.          rc.bottom += 3;
  998.          MapWindowPoints(pData->hWnd,hDlg,(POINT FAR *)&rc,2);       
  999.          InvalidateRect(hDlg,&rc,TRUE);         
  1000.         }    
  1001.         
  1002.         // show controls of new tab
  1003.         ptr = pTab->lpControls;
  1004.         while(ptr)
  1005.         {
  1006.          SetWindowPos(GetDlgItem(hDlg,ptr->wID),NULL,0,0,0,0,
  1007.                uFlags | SWP_SHOWWINDOW);
  1008.           
  1009.          ptr = ptr->next;
  1010.         }        
  1011.         
  1012.        // store pointer to active tab 
  1013.        pData->pActiveTab = pTab;
  1014.        
  1015.        // update area of tab
  1016.        CopyRect(&rc, &pData->pActiveTab->rcTab);
  1017.        rc.bottom += 3;
  1018.        MapWindowPoints(pData->hWnd,hDlg,(POINT FAR *)&rc,2);       
  1019.        InvalidateRect(hDlg,&rc,TRUE);       
  1020.     }
  1021.     else
  1022.         return FALSE;
  1023.  
  1024.  // let parent know that tab has changed
  1025.  NotifyParent(pData->hWnd, TABN_CHANGETAB) ;
  1026.  
  1027.  return (LRESULT)TRUE;
  1028. }
  1029.  
  1030. ///////////////////////////////////////////////////////////////////////////
  1031. // Function:    CalcTabRect
  1032. // Purpose:     calculates rectangle of top part of tab
  1033. // Parameters:  pData   -   pointer to tab control block
  1034. //              pTabPage    -   pointer to tab page
  1035. //
  1036. // Returns:     n/a
  1037. ///////////////////////////////////////////////////////////////////////////
  1038. void WINAPI CalcTabRect(LPTABCTLBLK pData,LPTABPAGE  pTabPage)
  1039. {
  1040.     WORD nTabWidth = GetWindowWord(pData->hWnd,GWW_TABWIDTH);
  1041.     HFONT      hFont, hOldFont;
  1042.     HDC        hdc;
  1043.     DWORD      dwExtents;
  1044.     WORD       nMaxWidth = 0;
  1045.  
  1046.     // get size of tab
  1047.     hFont = (HFONT)SendMessage(pData->hWnd,WM_GETFONT,0,0L);
  1048.     hdc = GetDC(NULL);
  1049.     hOldFont = (HFONT)SelectObject(hdc,hFont); 
  1050.    
  1051.     dwExtents = GetTextExtent(hdc, pTabPage->szCaption, lstrlen(pTabPage->szCaption));
  1052.    
  1053.     SelectObject(hdc,hOldFont); 
  1054.     ReleaseDC(NULL,hdc);
  1055.  
  1056.  if(pTabPage->prev == NULL)
  1057.     pTabPage->rcTab.left = 0;
  1058.  else
  1059.     pTabPage->rcTab.left = pTabPage->prev->rcTab.right + 1;
  1060.  
  1061.  pTabPage->rcTab.top = 0;
  1062.  pTabPage->rcTab.bottom = pData->wTabHeight;
  1063.  
  1064.  pTabPage->rcTab.right = pTabPage->rcTab.left + nTabWidth;
  1065.  
  1066.  pTabPage->rcCaption.left = 0;
  1067.  pTabPage->rcCaption.top = 0;
  1068.  pTabPage->rcCaption.right = LOWORD(dwExtents) + 4;
  1069.  pTabPage->rcCaption.bottom = HIWORD(dwExtents) + 4;
  1070.  
  1071.  OffsetRect(&pTabPage->rcCaption, 
  1072.         pTabPage->rcTab.left + ((pTabPage->rcTab.right - pTabPage->rcTab.left) - (pTabPage->rcCaption.right - pTabPage->rcCaption.left))/2,
  1073.         ((pTabPage->rcTab.bottom - pTabPage->rcTab.top) - (pTabPage->rcCaption.bottom - pTabPage->rcCaption.top))/2);
  1074.  
  1075. }
  1076.  
  1077. ///////////////////////////////////////////////////////////////////////////
  1078. // Function:    DrawUpTab
  1079. // Purpose:     draws tab in up position
  1080. // Parameters:  hdc     -   device context to draw on
  1081. //              pData   -   pointer to tab control block
  1082. //              pTabPage -  ponter to tab page
  1083. //
  1084. // Returns:     n/a
  1085. ///////////////////////////////////////////////////////////////////////////
  1086. void WINAPI DrawUpTab(HDC hdc, LPTABCTLBLK pData,LPTABPAGE  pTabPage, HPEN *pPens)
  1087.  POINT  pt[6];
  1088.  HPEN   hOldPen;
  1089.  LPRECT lprc;
  1090.  
  1091.  // up tab is down tab with a few more lines around the inside of tab
  1092.  DrawDownTab(hdc,pData,pTabPage,pPens);
  1093.  
  1094.  lprc = &pTabPage->rcTab;
  1095.  
  1096.  hOldPen = SelectObject(hdc,pPens[PEN_WHITE]);
  1097.  
  1098.  pt[0].x = lprc->left + 2;
  1099.  pt[0].y = lprc->bottom; 
  1100.  
  1101.  pt[1].x = lprc->left + 2;
  1102.  pt[1].y = lprc->top + 4;
  1103.  
  1104.  pt[2].x = lprc->left + 4;
  1105.  pt[2].y = lprc->top + 2;
  1106.  
  1107.  pt[3].x = lprc->right - 4;
  1108.  pt[3].y = lprc->top + 2;
  1109.  
  1110.  Polyline(hdc,(LPPOINT)&pt,4); 
  1111.  
  1112.  pt[0].x = lprc->left + 3;
  1113.  pt[0].y = lprc->top + 4;
  1114.  
  1115.  pt[1].x = lprc->left + 5;
  1116.  pt[1].y = lprc->top + 2;
  1117.  
  1118.  Polyline(hdc,(LPPOINT)&pt,2); 
  1119.    
  1120.  SelectObject(hdc,pPens[PEN_SHADOW]); 
  1121.  
  1122.  pt[0].x = lprc->right - 4 ;
  1123.  pt[0].y = lprc->top + 2;
  1124.  
  1125.  pt[1].x = lprc->right - 2;
  1126.  pt[1].y = lprc->top + 4;
  1127.  
  1128.  pt[2].x = lprc->right - 2;
  1129.  pt[2].y = lprc->bottom + 1; 
  1130.  
  1131.  Polyline(hdc,(LPPOINT)&pt,3); 
  1132.  
  1133.  pt[0].x = lprc->right - 4 ;
  1134.  pt[0].y = lprc->top + 3;
  1135.  
  1136.  pt[1].x = lprc->right - 2 ;
  1137.  pt[1].y = lprc->top + 5;
  1138.  
  1139.  Polyline(hdc,(LPPOINT)&pt,2); 
  1140.  
  1141.  SelectObject(hdc,hOldPen);
  1142. }
  1143.  
  1144. ///////////////////////////////////////////////////////////////////////////
  1145. // Function:    DrawDownTab
  1146. // Purpose:     draws tab in down position
  1147. // Parameters:  hdc     -   device context to draw on
  1148. //              pData   -   pointer to tab control block
  1149. //              pTabPage -  ponter to tab page
  1150. //
  1151. // Returns:     n/a
  1152. ///////////////////////////////////////////////////////////////////////////
  1153. void WINAPI DrawDownTab(HDC hdc, LPTABCTLBLK pData,LPTABPAGE  pTabPage, HPEN *pPens)
  1154. {
  1155.  POINT  pt[6];
  1156.  HPEN   hOldPen;
  1157.  LPRECT lprc;
  1158.  
  1159.  lprc = &pTabPage->rcTab;
  1160.  
  1161.  hOldPen = SelectObject(hdc,pPens[PEN_BLACK]);
  1162.  
  1163.  pt[0].x = lprc->left;
  1164.  //pt[0].y = lprc->bottom;
  1165.  pt[0].y = lprc->bottom - 2;
  1166.  
  1167.  pt[1].x = lprc->left;
  1168.  pt[1].y = lprc->top + 4;
  1169.  
  1170.  pt[2].x = lprc->left + 4;
  1171.  pt[2].y = lprc->top;
  1172.  
  1173.  pt[3].x = lprc->right - 4;
  1174.  pt[3].y = lprc->top;
  1175.  
  1176.  pt[4].x = lprc->right;
  1177.  pt[4].y = lprc->top + 4;
  1178.  
  1179.  pt[5].x = lprc->right;
  1180.  pt[5].y = lprc->bottom;
  1181.  
  1182.  Polyline(hdc,(LPPOINT)&pt,6);
  1183.  
  1184.  SelectObject(hdc,pPens[PEN_WHITE]);
  1185.  
  1186.  pt[0].x = lprc->left + 1;
  1187.  pt[0].y = lprc->bottom;
  1188.  
  1189.  pt[1].x = lprc->left + 1;
  1190.  pt[1].y = lprc->top + 4;
  1191.  
  1192.  pt[2].x = lprc->left + 4;
  1193.  pt[2].y = lprc->top + 1;
  1194.  
  1195.  pt[3].x = lprc->right - 3;
  1196.  pt[3].y = lprc->top + 1;
  1197.  
  1198.  Polyline(hdc,(LPPOINT)&pt,4);
  1199.  
  1200.  SelectObject(hdc,pPens[PEN_SHADOW]); 
  1201.  
  1202.  pt[0].x = lprc->right - 3 ;
  1203.  pt[0].y = lprc->top + 2;
  1204.  
  1205.  pt[1].x = lprc->right - 1;
  1206.  pt[1].y = lprc->top + 4;
  1207.  
  1208.  pt[2].x = lprc->right - 1;
  1209.  pt[2].y = lprc->bottom + 1;
  1210.  
  1211.  Polyline(hdc,(LPPOINT)&pt,3);
  1212.     
  1213.  SelectObject(hdc, hOldPen);
  1214. }
  1215.  
  1216.  
  1217.  
  1218. ///////////////////////////////////////////////////////////////////////////
  1219. // Function:    OnLButtonDown
  1220. // Purpose:     responds to WM_LBUTTONDOWN
  1221. // Parameters:  pData   -   pointer to tab control block
  1222. //              x,y     -   coordinate of click
  1223. //
  1224. // Returns:     0
  1225. ///////////////////////////////////////////////////////////////////////////
  1226. LRESULT OnLButtonDown(LPTABCTLBLK pData, POINT  *lpPt)
  1227. {
  1228.     LPTABPAGE   ptr;
  1229.     
  1230.     SetFocus(pData->hWnd);
  1231.     
  1232.     if(lpPt->y > (int)pData->wTabHeight)
  1233.         return 0L;
  1234.  
  1235.     ptr = pData->lpHead;
  1236.     while(ptr)
  1237.     {
  1238.      if(PtInRect(&ptr->rcTab,*lpPt))
  1239.      {
  1240.         if(pData->pActiveTab != ptr)
  1241.             SendMessage(pData->hWnd,TAB_SETCURSEL,ptr->wIndex,0L);
  1242.         return 0L;
  1243.      }
  1244.     ptr = ptr->next;
  1245.     }
  1246.     return 0L;
  1247. }
  1248.  
  1249.  
  1250. ///////////////////////////////////////////////////////////////////////////
  1251. // Function:    DrawTabText
  1252. // Purpose:     draw caption text
  1253. // Parameters:  hdc -   device context
  1254. //              pData - pointer to tab control block
  1255. //              pTabPage - pointer to tab page
  1256. //
  1257. // Returns:     n/a
  1258. ///////////////////////////////////////////////////////////////////////////
  1259. void WINAPI DrawTabText(HDC hdc, LPTABCTLBLK pData,LPTABPAGE  pTabPage)
  1260. {
  1261.     int bk_mode;
  1262.     HFONT   hOldFont;
  1263.     COLORREF   cwOld;
  1264.     
  1265.     bk_mode = SetBkMode(hdc,TRANSPARENT);
  1266.     if(pData->pActiveTab == pTabPage)
  1267.     {
  1268.         hOldFont = (HFONT)SelectObject(hdc,GetActiveTabFont(pData->hWnd));
  1269.         if(GetFocus() == pData->hWnd)
  1270.             DrawFocusRect(hdc,&pData->pActiveTab->rcCaption);
  1271.     }
  1272.     else
  1273.         hOldFont = (HFONT)SelectObject(hdc,GetDepressedTabFont());
  1274.     
  1275.     /* draw white text to give chisled look */
  1276.     cwOld = SetTextColor(hdc,RGB(0xFF,0xFF,0xFF));
  1277.  
  1278.     if(pData->bShadow)
  1279.     {
  1280.         OffsetRect(&pTabPage->rcCaption,1,1);
  1281.          DrawText(hdc,pTabPage->szCaption,lstrlen(pTabPage->szCaption),&pTabPage->rcCaption,
  1282.             DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  1283.         /* shift up and to the left */
  1284.         OffsetRect(&pTabPage->rcCaption,-1,-1);
  1285.     }     
  1286.  
  1287.     /* use black text */
  1288.     SetTextColor(hdc,RGB(0x00,0x00,0x00));
  1289.     
  1290.     DrawText(hdc,pTabPage->szCaption,lstrlen(pTabPage->szCaption),&pTabPage->rcCaption,
  1291.             DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  1292.     
  1293.     /* restore old text color */
  1294.     SetTextColor(hdc,cwOld);
  1295.  
  1296.     SelectObject(hdc,hOldFont);
  1297.     SetBkMode(hdc,bk_mode);
  1298. }
  1299.  
  1300. ///////////////////////////////////////////////////////////////////////////
  1301. // Function:    NotifyParent
  1302. // Purpose:     sends notification message to parent
  1303. // Parameters:  hWndControl -   window handle of control
  1304. //              wNotifyCode -   notification code
  1305. //
  1306. // Returns:     return value from parent
  1307. ///////////////////////////////////////////////////////////////////////////
  1308. LRESULT WINAPI NotifyParent(HWND hWndControl, WORD wNotifyCode) 
  1309. {
  1310.    LRESULT lResult;
  1311.  
  1312.    lResult = SendMessage(GetParent(hWndControl), WM_COMMAND,
  1313.                GetWindowWord(hWndControl, GWW_ID),
  1314.                MAKELPARAM(hWndControl, wNotifyCode));
  1315.    return(lResult);
  1316. }
  1317.  
  1318.  
  1319. ///////////////////////////////////////////////////////////////////////////
  1320. // Function:    OnDeleteTab
  1321. // Purpose:     deletes tab from list of tabs
  1322. // Parameters:  pData   -   pointer to tab control block
  1323. //              wIndex  -   index of tab to delete
  1324. //
  1325. // Returns:     TRUE,FALSE
  1326. ///////////////////////////////////////////////////////////////////////////
  1327. LRESULT WINAPI OnDeleteTab(LPTABCTLBLK pData,WORD wIndex)                   
  1328. {
  1329.     LPTABPAGE ptr;
  1330.     RECT        rc;
  1331.     HWND        hDlg;
  1332.     
  1333.     ptr = GetTabByIndex(pData,wIndex);
  1334.     if(!ptr)
  1335.         return FALSE;
  1336.         
  1337.     if(ptr->prev)
  1338.         ptr->prev->next = ptr->next;
  1339.         
  1340.     if(ptr->next)
  1341.         ptr->next->prev = ptr->prev;
  1342.         
  1343.     if(pData->lpHead == ptr)
  1344.         pData->lpHead = ptr->next;
  1345.         
  1346.  
  1347.     if(pData->lpTail == ptr)
  1348.         pData->lpTail = ptr->prev;
  1349.     
  1350.     if(pData->pActiveTab == ptr)
  1351.         pData->pActiveTab = (ptr->next?ptr->next:ptr->prev);
  1352.  
  1353.     hDlg = GetParent(pData->hWnd);    
  1354.     GetClientRect(pData->hWnd,&rc);       
  1355.     InflateRect(&rc,-3,-3);
  1356.     MapWindowPoints(pData->hWnd,hDlg,(POINT FAR *)&rc,2);       
  1357.     InvalidateRect(hDlg,&rc,TRUE);   
  1358.     
  1359.     FreeTab(ptr);        
  1360.     
  1361.     return TRUE;
  1362. }
  1363.  
  1364. ///////////////////////////////////////////////////////////////////////////
  1365. // Function:    OnFindTab 
  1366. // Purpose:     returns index of tab with caption lpBuffer
  1367. // Parameters:  pData   -   pointer to tab control block
  1368. //              lpBuffer -  text to match
  1369. //
  1370. // Returns:     index on success
  1371. //              -1 on failure
  1372. ///////////////////////////////////////////////////////////////////////////
  1373. LRESULT WINAPI OnFindTab(LPTABCTLBLK pData,LPCSTR lpBuffer)
  1374. {
  1375.     LPTABPAGE ptr;
  1376.     
  1377.     ptr = pData->lpHead;
  1378.     
  1379.     while(ptr)
  1380.     {
  1381.         if(lstrcmpi(lpBuffer,ptr->szCaption) == 0)
  1382.             return ptr->wIndex;
  1383.         ptr = ptr->next;    
  1384.     
  1385.     }
  1386.      return (LRESULT)-1;
  1387.  
  1388. }
  1389.  
  1390. ///////////////////////////////////////////////////////////////////////////
  1391. // Function:    OnGetTextLength
  1392. // Purpose:     get length of caption of tab wIndex
  1393. // Parameters:  pData   -   pointer to tab control block
  1394. //              wIndex  -   index of tab
  1395. //
  1396. // Returns:     length of tab or zero on failure
  1397. ///////////////////////////////////////////////////////////////////////////
  1398. LRESULT WINAPI OnGetTextLength(LPTABCTLBLK pData,WORD wIndex)
  1399. {
  1400.     LPTABPAGE ptr;
  1401.     
  1402.     ptr = GetTabByIndex(pData,wIndex);
  1403.     if(ptr)
  1404.         return lstrlen(ptr->szCaption);
  1405.     
  1406.     return 0L;
  1407. }
  1408.  
  1409. ///////////////////////////////////////////////////////////////////////////
  1410. // Function:    OnGetText
  1411. // Purpose:     copy text of tab into buffer
  1412. // Parameters:  pData   -   pointer to tab control block
  1413. //              wIndex  -   index of tab
  1414. //              lpBuffer -  buffer to copy text to
  1415. //
  1416. // Returns:     TRUE/FALSE
  1417. ///////////////////////////////////////////////////////////////////////////
  1418. LRESULT WINAPI OnGetText(LPTABCTLBLK pData,WORD wIndex,LPSTR lpBuffer)
  1419. {
  1420.     LPTABPAGE ptr;
  1421.     
  1422.     ptr = GetTabByIndex(pData,wIndex);
  1423.  
  1424.     if(ptr)
  1425.     {
  1426.         lstrcpy(lpBuffer,ptr->szCaption);    
  1427.         return TRUE;
  1428.     }
  1429.     return FALSE;
  1430. }
  1431.  
  1432.  
  1433.  
  1434. ///////////////////////////////////////////////////////////////////////////
  1435. // Function:    GetTabByIndex
  1436. // Purpose:     returns pointer to tab with index of wIndex
  1437. // Parameters:  pData   -   pointer to tab control block
  1438. //              wIndex  -   index of tab to find
  1439. //
  1440. // Returns:     NULL or pointer to tab
  1441. ///////////////////////////////////////////////////////////////////////////
  1442. LPTABPAGE GetTabByIndex(LPTABCTLBLK pData,WORD wIndex)
  1443. {
  1444.     LPTABPAGE ptr;
  1445.     
  1446.     ptr = pData->lpHead;
  1447.     
  1448.     while(ptr)
  1449.     {
  1450.         if(ptr->wIndex == wIndex)
  1451.             return ptr;
  1452.         ptr = ptr->next;    
  1453.     
  1454.     }
  1455.      return NULL;
  1456. }
  1457.  
  1458.  
  1459. WORD CalcTabWidth(LPTABCTLBLK pData)
  1460. {
  1461.     LPTABPAGE   ptr;                
  1462.     HFONT      hFont, hOldFont;
  1463.     HDC        hdc;
  1464.     DWORD      dwExtents;
  1465.     WORD       nMaxWidth = 0;
  1466.  
  1467.     // get size of tab
  1468.     hFont = (HFONT)SendMessage(pData->hWnd,WM_GETFONT,0,0L);
  1469.     hdc = GetDC(NULL);
  1470.     hOldFont = (HFONT)SelectObject(hdc,hFont); 
  1471.    
  1472.     for(ptr = pData->lpHead; ptr != NULL; ptr = ptr->next)
  1473.     {
  1474.         dwExtents = GetTextExtent(hdc, ptr->szCaption, lstrlen(ptr->szCaption));
  1475.         if(LOWORD(dwExtents) > nMaxWidth)
  1476.             nMaxWidth = LOWORD(dwExtents);   
  1477.     }
  1478.    
  1479.     SelectObject(hdc,hOldFont); 
  1480.     ReleaseDC(NULL,hdc);
  1481.    
  1482.     nMaxWidth += (2*WIDTH_FUDGE + 4);
  1483.     
  1484.     return nMaxWidth;
  1485. }